﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Entity;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using OAuth;
using System.Net;
using System.Web;

namespace BusinessLogic
{
    public class UserCredentialLogic
    {
        public class AuthorizationException : Exception
        {
        }
        #region Const
        private static string folderName = "Avatar";
        private static string filename = "credential.uci";
        private static Uri requestTokenUri = new Uri("http://www.douban.com/service/auth/request_token");
        private static Uri accessTokenUri = new Uri("http://www.douban.com/service/auth/access_token");
        private static string authorizationUri = "http://www.douban.com/service/auth/authorize?oauth_token=";
        #endregion
        
        #region  normal field
        private static OAuthBase oAuth = new OAuthBase();
        #endregion

        public string AuthorizationUri { get { return authorizationUri; } }
        public OAuthBase OAuth { get { return oAuth; } }

        #region UserCredential
        private static String GetUserCredentialFileFolder()
        {
            String myDocument = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
            String folderPath = Path.Combine(myDocument, folderName);
            if (!Directory.Exists(folderPath))
            {
                Directory.CreateDirectory(folderPath);
            }
            return folderPath;
        }
        public static void SaveUserCredentialInfo(UserCredential userCredential)
        {
            string filePath = Path.Combine(GetUserCredentialFileFolder(), filename);
            FileStream fs = new FileStream(filePath, FileMode.Create);
            BinaryFormatter formatter = new BinaryFormatter(null,
                new StreamingContext(StreamingContextStates.CrossAppDomain));
            try
            {
                formatter.Serialize(fs, userCredential);
            }
            catch (SerializationException e)
            {
                throw;
            }
            finally
            {
                fs.Close();
            }
        }
        public static void DestroyCredentialInfo()
        {
            string filePath = Path.Combine(GetUserCredentialFileFolder(), filename);
            if (File.Exists(filePath)) File.Delete(filePath);
        }
        public static UserCredential LoadUserCredentialInfo()
        {
            UserCredential userCredential = null;
            string filePath = Path.Combine(GetUserCredentialFileFolder(), filename);
            if (File.Exists(filePath))
            {
                FileStream fs = new FileStream(filePath, FileMode.Open);
                
                try
                {
                    if (fs.Length > 0)
                    {//文件不是空的
                        BinaryFormatter formatter = new BinaryFormatter(null,
                        new StreamingContext(StreamingContextStates.CrossAppDomain));
                        userCredential = (UserCredential)formatter.Deserialize(fs);
                    }
                }
                catch (SerializationException e)
                {
                    throw;
                }
                finally
                {
                    fs.Close();
                }
            }
            return userCredential;
        }
        #endregion

        #region User Authorize
        private static Dictionary<string, string> ParseResponse(string parameters)
        {
            Dictionary<string, string> result = new Dictionary<string, string>();

            if (!string.IsNullOrEmpty(parameters))
            {
                string[] p = parameters.Split('&');
                foreach (string s in p)
                    if (!string.IsNullOrEmpty(s))
                        if (s.IndexOf('=') > -1)
                        {
                            string[] temp = s.Split('=');
                            result.Add(temp[0], temp[1]);
                        }
                        else result.Add(s, string.Empty);
            }

            return result;
        }

        /// <summary>
        /// credential 参数将保存取得的 Request Token
        /// </summary>
        /// <param name="credential"></param>
        public void GetRequestToken(UserCredential credential) 
        {
            //检查参数是否合法
            if (credential == null) return;

            Uri uri = requestTokenUri;
            string nonce = oAuth.GenerateNonce();
            string timeStamp = oAuth.GenerateTimeStamp();
            string normalizeUrl, normalizedRequestParameters;
            string apiKey = UserCredential.ApiKey;
            string apiKeySecret = UserCredential.ApiKeySecret;

            // 签名 
            string sig = oAuth.GenerateSignature(
                uri,
                apiKey,
                apiKeySecret,
                string.Empty,
                string.Empty,
                "GET",
                timeStamp,
                nonce,
                OAuthBase.SignatureTypes.HMACSHA1,
                out normalizeUrl,
                out normalizedRequestParameters);
            sig = HttpUtility.UrlEncode(sig);

            //构造请求Request Token的url 
            StringBuilder sb = new StringBuilder(uri.ToString());
            sb.AppendFormat("?oauth_consumer_key={0}&", apiKey);
            sb.AppendFormat("oauth_nonce={0}&", nonce);
            sb.AppendFormat("oauth_timestamp={0}&", timeStamp);
            sb.AppendFormat("oauth_signature_method={0}&", "HMAC-SHA1");
            sb.AppendFormat("oauth_version={0}&", "1.0");
            sb.AppendFormat("oauth_signature={0}", sig);

            //请求Request Token 
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(sb.ToString());
            StreamReader stream = null;
            HttpWebResponse response = null;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
                stream = new StreamReader(response.GetResponseStream(), System.Text.Encoding.UTF8);
                string responseBody = stream.ReadToEnd();

                //解析返回的Request Token和Request Token Secret 
                Dictionary<string, string> responseValues = ParseResponse(responseBody);
                credential.RequestToken = responseValues["oauth_token"];
                credential.RequestTokenSecret = responseValues["oauth_token_secret"];
            }
            catch (WebException e)
            {
                throw;
            }
            finally
            {
                stream = null;
                response = null;
            }
        }

        /// <summary>
        /// credential 参数将保存取得的 Access Token
        /// </summary>
        /// <param name="credential"></param>
        public static void GetAccessToken(UserCredential credential) 
        {
            //此方法调用前提是credential request token 以及密钥已经取得
            if (credential == null || string.IsNullOrEmpty(credential.RequestToken) || string.IsNullOrEmpty(credential.RequestTokenSecret))  return;
            
            Uri uri = accessTokenUri;
            string nonce = oAuth.GenerateNonce();
            string timeStamp = oAuth.GenerateTimeStamp();
            string normalizeUrl, normalizedRequestParameters;
            string apiKey = UserCredential.ApiKey ;
            string apiKeySecret = UserCredential.ApiKeySecret;
            string requestToken = credential.RequestToken;
            string requestTokenSecret = credential.RequestTokenSecret;

            // 签名 
            string sig = oAuth.GenerateSignature(
                uri,
                apiKey,
                apiKeySecret,
                requestToken,
                requestTokenSecret,
                "GET",
                timeStamp,
                nonce,
                OAuthBase.SignatureTypes.HMACSHA1,
                out normalizeUrl,
                out normalizedRequestParameters);
            sig = HttpUtility.UrlEncode(sig);

            //构造请求Access Token的url 
            StringBuilder sb = new StringBuilder(uri.ToString());
            sb.AppendFormat("?oauth_consumer_key={0}&", apiKey);
            sb.AppendFormat("oauth_nonce={0}&", nonce);
            sb.AppendFormat("oauth_timestamp={0}&", timeStamp);
            sb.AppendFormat("oauth_signature_method={0}&", "HMAC-SHA1");
            sb.AppendFormat("oauth_version={0}&", "1.0");
            sb.AppendFormat("oauth_signature={0}&", sig);
            sb.AppendFormat("oauth_token={0}&", requestToken);

            //请求Access Token 
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(sb.ToString());
            HttpWebResponse response = null;
            StreamReader stream = null;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
                stream = new StreamReader(response.GetResponseStream(), System.Text.Encoding.UTF8);
                string responseBody = stream.ReadToEnd();

                //解析返回的Request Token和Request Token Secret 
                Dictionary<string, string> responseValues = ParseResponse(responseBody);
                credential.AccessToken = responseValues["oauth_token"];
                credential.AccessTokenSecret = responseValues["oauth_token_secret"];
            }
            catch (WebException e)
            {
                throw;
                throw new AuthorizationException();
            }
            finally
            {
                stream = null;
                response = null;
            }
        }
        #endregion
        /// <summary>
        /// 
        /// </summary>
        /// <param name="apiUrl"></param>
        /// <param name="apiKey"></param>
        /// <param name="apiKeySecret"></param>
        /// <param name="accessToken"></param>
        /// <param name="accessTokenSecret"></param>
        /// <returns></returns>
        public static string SignAPICall(string apiUrl, string apiKey, string apiKeySecret, string accessToken, string accessTokenSecret)
        {

            string signedAPIUrl = null;
            Uri apiUri = new Uri(apiUrl);
            string nonce = oAuth.GenerateNonce();
            string timeStamp = oAuth.GenerateTimeStamp();
            string normalizeUrl, normalizedRequestParameters;

            string sig = oAuth.GenerateSignature(
                apiUri,
                apiKey,
                apiKeySecret,
                accessToken,
                accessTokenSecret,
                "GET",
                timeStamp,
                nonce,
                OAuthBase.SignatureTypes.HMACSHA1,
                out normalizeUrl,
                out normalizedRequestParameters);
            sig = HttpUtility.UrlEncode(sig);

            //构造OAuth头部 
            StringBuilder oauthHeader = new StringBuilder(apiUrl);
            oauthHeader.AppendFormat("OAuth realm=\"\", oauth_consumer_key={0}, ", apiKey);
            oauthHeader.AppendFormat("oauth_nonce={0}, ", nonce);
            oauthHeader.AppendFormat("oauth_timestamp={0}, ", timeStamp);
            oauthHeader.AppendFormat("oauth_signature_method={0}, ", "HMAC-SHA1");
            oauthHeader.AppendFormat("oauth_version={0}, ", "1.0");
            oauthHeader.AppendFormat("oauth_signature={0}, ", sig);
            oauthHeader.AppendFormat("oauth_token={0}", accessToken);

            signedAPIUrl = oauthHeader.ToString();  //based on api url

            return signedAPIUrl;
        }
    }
}
